package com.zzx.auth.oauth2;

import com.zzx.common.enums.ConstantEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.DataType;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 自定义jwt实现
 **/
@Slf4j
public class CustomJwtTokenStore extends JwtTokenStore {

    private static String LOGIN_USER_PREFIX = "saas:login:";

    @Autowired
    StringRedisTemplate template;


    public CustomJwtTokenStore(JwtAccessTokenConverter jwtTokenEnhancer) {
        super(jwtTokenEnhancer);
    }

    /**
     * 自定义Token存储
     */
    @Override
    public void storeAccessToken(OAuth2AccessToken token, OAuth2Authentication authentication) {
        // 对于JWT 其实是不需要存储的，但是有需要存储可以在该方法中实现

        // 当前登录用户
        LoginUser user = (LoginUser) authentication.getUserAuthentication().getPrincipal();
        // 获取当前登录用户唯一标识
        Map<String, Object> data = token.getAdditionalInformation();
        String code = (String) data.get("code");
        String scope = (String) data.get("scope");
        String userLogin = LOGIN_USER_PREFIX + user.getUserId();
        //由于之前存储的是string  现在多端登录存储的结构为map 所以需要判断一下
        if (template.hasKey(userLogin)) {
            DataType dataType = template.type(userLogin);
            if (!dataType.code().equals(DataType.HASH.code())) {
                template.delete(userLogin);
            }
        }
        log.info("用户ID：{}，用户端：{}", userLogin, scope);
        HashOperations<String, String, String> opsForHash = template.opsForHash();
        Map<String, String> map = opsForHash.entries(userLogin);
        if (map == null) {
            map = new HashMap<>(6);
        }
        map.put(scope, code);
        opsForHash.putAll(userLogin, map);
        template.expire(userLogin, ConstantEnum.REDISCODE.getValue(), TimeUnit.DAYS);
        log.info("用户 {} 登录标识 {}", user.getUsername(), code);
        super.storeAccessToken(token, authentication);
    }

    /**
     * 自定义删除token - 登出功能
     * Jwt 中是没有默认实现方法
     */
    @Override
    public void removeAccessToken(OAuth2AccessToken token) {
        Object user_id = token.getAdditionalInformation().get("user_id");
        template.delete(LOGIN_USER_PREFIX + user_id);
        super.removeAccessToken(token);
    }
}
